<?php
/*
 +-----------------------------------------------
 |拔河游戏设置
 +-----------------------------------------------
 | Auth: dark2light@qq.com
 | Date: 2017.3.12
 +-----------------------------------------------
 |Main: 拔河游戏设置，其他一些杂项本不该放在这里。
 +-----------------------------------------------
*/
namespace Tug\Controller;

use Tug\Utils\InputUtils;
use Plume\Core\Controller;
use Plume\Core\Service;
use Plume\Core\Dao;

class BhDetailsController extends Controller
{
    private $redis;
    private $gameSetService;
    private $teamsService;
    private $gameStatusService;
    public function __construct($app) {
        parent::__construct($app);
        //使用默认Service和默认DAO
        $this->gameSetService = new Service($app, new Dao($app, 'game_set'));
        $this->teamsService = new Service($app, new Dao($app, 'teams'));
        $this->gameStatusService = new Service($app, new Dao($app, 'game_status'));
        $this->redis = new \Redis();
        $redisInfo = $this->getConfigValue('redis');
        if (!$this->redis->connect($redisInfo['host'], $redisInfo['port'])) {
           file_put_contents('redis_error.txt', date('Y-m-d H:i:s').'redis连接错误！'.PHP_EOL, 8);
        }
        session_start();
    }
    // 拔河游戏设置页数据回显
    public function indexAction()
    {
        try {
            $must = ['meet_id', 'sequence'];
            list($meetId, $sequence) = InputUtils::issetOrFail('get', $must);
            $_SESSION['meet_id'] = $meetId;
            $_SESSION['sequence'] = $sequence;

            $where = ['sequence' => $sequence];
            $redWhere = ['sequence' => $sequence, 'type' => 1];
            $blueWhere = ['sequence' => $sequence, 'type' => 2];
            $gameInfo = $this->gameSetService->fetch($where);
            $redInfo = $this->teamsService->fetch($redWhere);
            $blueInfo = $this->teamsService->fetch($blueWhere);
            if (!empty($gameInfo)) {
                $bkData = array(
                    'gameInfo' => $gameInfo[0], 'redInfo' =>$redInfo[0],
                    'blueInfo' => $blueInfo[0] ,'reCode' => 1,'end' => 999, 'mf' => 1
                );
            } else {
                $gameInfo = ['limit' => 50, 'bgMusic' => 1, 'gameTime' => 60];
                $redInfo = ['team_name'=>'红队', 'team_image'=> '/img/red.png'];
                $blueInfo = ['team_name'=>'蓝队', 'team_image'=> '/img/blue.png'];
                $bkData = array(
                    'gameInfo' =>$gameInfo , 'redInfo' => $redInfo,
                    'blueInfo' => $blueInfo , 'reCode' => 1,'end' => 999, 'mf' => 1
                );
            }
        } catch (\Exception $e) {
            $bkData = ['code' => -1, 'msg' => $e->getMessage()];
            exit(json_encode($bkData));
        }
        return $this->result($bkData)->response();
    }
    // 更新拔河游戏设置
    public  function updateDetailsAction()
    {
        try {
            $redis = $this->redis;
            $_POST['meet_id'] = isset($_SESSION['meet_id']) ? $_SESSION['meet_id'] : null;
            $_POST['sequence']  = isset($_SESSION['sequence']) ? $_SESSION['sequence'] : null;
            $must = ["meet_id", 'sequence', "playtime", "bgmusic", 'resultnum', 'teamData'];
            list($meetId,$sequence,$playtime,$bgmusic,$resultnum,$teamData) = InputUtils::issetOrFail("post", $must);
            $gameInfo = [
                'sequence'=>$sequence, 'meet_id'=> $meetId,
                'gameTime' => $playtime, 'bgMusic' => $bgmusic, 'limit' => $resultnum
            ];
            $redTeamInfo = [
                'sequence' => $sequence, 'team_name' => $teamData['A_name'],
                'team_image' =>  $teamData['A_img'], 'type' => 1
            ];
            $blueTeamInfo = [
                'sequence' => $sequence, 'team_name' => $teamData['B_name'],
                'team_image' =>  $teamData['B_img'], 'type' => 2
            ];
            $this->gameSetService->beginTransaction(); // 数据库事务
            $this->teamsService->delete(array('sequence' => $sequence));
            $this->gameSetService->delete(array('sequence' => $sequence));
            $bool = $this->teamsService->insert($redTeamInfo);
            $bool2 = $this->teamsService->insert($blueTeamInfo);
            $bool3 = $this->gameSetService->insert($gameInfo);

            $gameInfoKey = "game_set:{$meetId}_{$sequence}";
            $redTeamInfoKey = "teams:{$sequence}_1";
            $blueTeamInfoKey = "teams:{$sequence}_2";
            $dataInRedis = $redis->hGet($gameInfoKey, 'sequence');
            $rBool = $rBool2 = $rBool3 = true;
            if ($dataInRedis !== false) {
                $redis->multi();
                $rBool = $redis->hMset($gameInfoKey, $gameInfo); // 设置游戏的总信息，一个游戏对应两个队伍。
                $rBool2 = $redis->hMset($redTeamInfoKey, $redTeamInfo);
                $rBool3 = $redis->hMset($blueTeamInfoKey, $blueTeamInfo);
            }
            if ($bool && $bool2 && $bool3 && $rBool && $rBool2 && $rBool3) {
                $this->gameSetService->commitTransaction();
                $redis->exec();
                $bkDt = ['reCode' => 0];
            } else {
                $this->gameSetService->rollbackTransaction();
                $redis->discard();
                $bkDt = ['reCode' => -1];
                file_put_contents('task_error.txt',date("Y-m-d H:i:s")."\r\n", 8);
            }
        } catch (\Exception $e) {
            $bkDt = ['code' => -1, 'msg' => $e->getMessage(), 'errLine' => $e->getLine()];
        }
        exit(json_encode($bkDt));
    }
    // 控制台按钮显示控制，初始化游戏数据，将数据库中的数据放入Redis中提升速度。
    public function controlAction()
    {
        $redis = $this->redis;
        $httpServer = $this->getConfigValue('display_url');
        $requestType = $_SERVER["REQUEST_METHOD"] == "POST" ? 'post' : 'get';
        try {
            $must = ["meet_id", 'sequence'];
            list($meetId,$sequence) = InputUtils::issetOrFail($requestType, $must);
            $gameInfoKey = "game_set:{$meetId}_{$sequence}";
            $gameInfo = $redis->hGet($gameInfoKey, 'sequence');
            $roundKey = "game_round:{$meetId}_{$sequence}";
            if ($gameInfo === false) {  // 如果Redis中没有游戏数据
                $where = ['sequence' => $sequence];
                $gameInfo =$this->gameSetService->fetch($where);
                if (!empty($gameInfo)) { // 如果游戏被设置过。并且Redis中没有数据！
                    $teamInfo = $this->teamsService->fetch($where);
                    $gameRound = "select max(round) as round from game_status where sequence = '{$sequence}'";
                    $gameRound = $this->gameStatusService->queryBySql($gameRound);
                    $gameRound = isset($gameRound[0]['round']) ? $gameRound[0]['round']+1 : 1;
                    $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_{$gameRound}";
                    $gameStatusInfo = [
                        'sequence' => $sequence, 'status' => 1, 'win' => 0,
                        'blue_score'=> '0', 'red_score' => 0, 'round' => $gameRound
                    ];
                    $redTeamInfo = [];  $blueTeamInfo = [];
                    foreach ($teamInfo as $team) {
                        if ($team['type'] == 1) {
                            $redTeamInfo = $team;
                        } else {
                            $blueTeamInfo = $team;
                        }
                    }
                    $redTeamInfoKey = "teams:{$sequence}_1";
                    $blueTeamInfoKey = "teams:{$sequence}_2";
                    $gameInfoKey = "game_set:{$meetId}_{$sequence}";
                    $redis->multi();
                    $bool1 = $redis->hMset($redTeamInfoKey, $redTeamInfo); 
                    $bool2 =  $redis->hMset($blueTeamInfoKey, $blueTeamInfo);
                    $bool3 = $redis->hMset($gameInfoKey, $gameInfo[0]);
                    $bool4 = $redis->hMset($gameStatusInfoKey, $gameStatusInfo);
                    $bool5 = $redis->set($roundKey, $gameRound);
                    // 设置Redis中的失效时间为第二天凌晨三点
                    $time = time();
                    $year = date("Y", $time);
                    $month = (int)date("m", $time);
                    $day = date("d", $time);
                    $expire = mktime(5,0,0,$month,$day+1,$year)-time();
                    $redis->expire($redTeamInfoKey, $expire);
                    $redis->expire($blueTeamInfoKey, $expire);
                    $redis->expire($gameInfoKey, $expire);
                    $redis->expire($gameStatusInfoKey, $expire);
                    $redis->expire($roundKey, $expire);
                    if ($bool1  && $bool2 && $bool3 && $bool4 && $bool5){
                        $redis->exec();
                    } else {
                        $redis->discard();
                    }
                }
            }
            $round = $redis->get($roundKey);
            $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_$round";
            $gameStatusInfo= $redis->hMGet($gameStatusInfoKey, ['status', 'startTime', 'overTime']);
            $gameStatus = $gameStatusInfo['status'];
            $overTime = $gameStatusInfo['overTime'];
            $now = time();
            if ($now >= $overTime && $overTime != false) {
                $bkDt = ['status' => 3, 'msg' => '显示再来一轮按钮！','http_server' => $httpServer];
            } else if ($gameStatus == 1) {
                $joinRedKey =  "user_red:{$sequence}_{$round}";
                $joinBlueKey =  "user_blue:{$sequence}_{$round}";
                $redLen = $redis->zCard($joinRedKey);
                $blueLen = $redis->zCard($joinBlueKey);
                if ($redLen == 0 || $blueLen == 0) { // 要做判断
                    // 裁剪用户放在开始动作上
                    $bkDt = ['status' => 0, 'msg' => '显示人数不足按钮！', 'http_server' => $httpServer];
                } else {
                    $bkDt = ['status' => 1, 'msg' => '显示红色开始按钮', 'http_server' => $httpServer];
                }
            } else if ($gameStatus == 2) {
                $bkDt = [
                    'status' => 2, 'msg' => '显示游戏已经开始', 'http_server' => $httpServer
                ];
            } else {
                $bkDt = ['status' => -1, 'msg' => '游戏不存在！', 'http_server' => $httpServer];
            }
        } catch (\Exception $e) {
            $bkDt = ['status' => -2, 'msg' => $e->getMessage()];
        }
        if ($requestType === 'post') {
            exit(json_encode($bkDt));
        } else {
            return $this->result($bkDt)->response();
        }
    }
    //游戏再来一次
    public function gameAgainAction()
    {
        try {
            $redis = $this->redis;
            $must = ['meet_id', 'sequence'];
            list($meetId, $sequence) = InputUtils::issetOrFail('post', $must);
            $roundKey = "game_round:{$meetId}_{$sequence}";
            $round = $redis->get($roundKey);
            $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_$round";
            $overTime = $redis->hGet($gameStatusInfoKey, 'overTime');
            $gameExists = $redis->hGet($gameStatusInfoKey, 'round');
            if ($gameExists != false && ($overTime == false || $overTime > time())){
                $bkDt =['recode' => -1,  'msg' => '上一轮游戏还没结束！'];
            } else {
                $gameStatus = $redis->hGet($gameStatusInfoKey, 'status');
                $round = $redis->get($roundKey);
                $isWritingKey = "isWriting:{$sequence}_$round";
                $isWriting = $redis->get($isWritingKey) ;
                $redis->multi();
                if ($gameStatus == 3 && $isWriting == 1) {
                    $round++;
                } else {
                     //没有正常结束的游戏，还是从当前轮数开始.
                    $joinRed =  "user_red:{$sequence}_{$round}";
                    $joinBlue =  "user_blue:{$sequence}_{$round}";
                    $redis->del($joinRed, $joinBlue);
                }
                $bool3 = $redis->set($roundKey, $round);
                $gameStatusInfo = [
                    'sequence' => $sequence, 'status' => 1, 'win' => 0,
                    'blue_score' => '0', 'red_score' => 0, 'round' => $round,
                ];
                $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_$round";
                $bool4 = $redis->hMset($gameStatusInfoKey, $gameStatusInfo);
                $bool5 = $redis->hDel($gameStatusInfoKey,'startTime', 'overTime'); // del start & over time
                if ($bool3 && $bool4 && $bool5) {
                    $redis->exec();
                    $bkDt = ['recode' => 1, 'msg' => '可以再来一次'];
                } else {
                    $redis->discard();
                    $bkDt = ['recode' => -1, 'msg' => '再来一次数据初始化失败'];
                }
            }
        }catch (\Exception $e) {
            $bkDt = ['recode' => -2, 'msg' => $e->getMessage()];
        }
        exit(json_encode($bkDt));
    }
    // 游戏开始
    public function gameStartAction()
    {
        try {
            $redis = $this->redis;
            $must = ['meet_id', 'sequence'];
            list($meetId, $sequence) = InputUtils::issetOrFail('post', $must);
            $roundKey = "game_round:{$meetId}_{$sequence}";
            $round = $this->redis->get($roundKey);
            $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_$round";
            $gameStatus = $redis->hGet($gameStatusInfoKey, 'status');
            $gameInfoKey = "game_set:{$meetId}_{$sequence}";
            $gameTime = (int)$redis->hGet($gameInfoKey, 'gameTime');
            if ($gameStatus == 1) { // game exists && is not begin
                $startTime = time();
                $joinRedKey =  "user_red:{$sequence}_{$round}";
                $joinBlueKey =  "user_blue:{$sequence}_{$round}";
                $redTeamLen = $redis->zCard($joinRedKey);
                $blueTeamLen = $redis->zCard($joinBlueKey);
                if ($redTeamLen !=0 && $blueTeamLen !=0) {
                    if ($redTeamLen > $blueTeamLen) { // 红蓝人数对其
                        $redis->zRemRangeByRank($joinRedKey,$blueTeamLen, -1);
                    } else {
                       $redis->zRemRangeByRank($joinBlueKey, $redTeamLen, -1);
                    }
                    $data = ['startTime' => $startTime, 'status' => 2, 'overTime' => $gameTime + $startTime + 5];
                    $bool = $redis->hMset($gameStatusInfoKey, $data);
                    if ($bool) {
                        $bkDt = ['recode'=> 1 , 'msg' => '游戏成功开始'];
                    } else {
                        $bkDt = ['recode'=> 0 , 'msg' => '开始游戏失败'];
                    }
                } else {
                    $bkDt = ['recode'=> -2 , 'msg' => '人数不足不能开始游戏！'];
                }
            } else {
                $bkDt = ['recode'=> -1 , 'msg' => '游戏进行中或已结束！'];
            }
        } catch (\Exception $e) {
            $bkDt =['recode' => -300, 'status' => 0, 'msg' => $e->getMessage()];
        }
        exit(json_encode($bkDt));
    }
    // 添加兵器初始化方法
    public function initAction()
    {
        $meetId = $this->getParamValue('meet_id');
        $sequence = $this->getParamValue('sequence');
        if (empty($sequence)) {
            try {
                $sequence = $this->id();
                $gameInfo = [
                    'sequence' => $sequence, 'meet_id' => $meetId,
                    'gameTime' => 60, 'bgMusic' => 1, 'limit' => 50
                ];
                $redTeamInfo = [
                    'sequence' => $sequence, 'team_name' => '红队',
                    'team_image' => '/img/red.png', 'type' => 1
                ];
                $blueTeamInfo = [
                    'sequence' => $sequence, 'team_name' => '蓝队',
                    'team_image' => '/img/blue.png', 'type' => 2
                ];
                $this->gameSetService->beginTransaction();
                $this->teamsService->delete(array('sequence' => $sequence));
                $this->gameSetService->delete(array('sequence' => $sequence));
                $bool = $this->teamsService->insert($redTeamInfo);
                $bool2 = $this->teamsService->insert($blueTeamInfo);
                $bool3 = $this->gameSetService->insert($gameInfo);
                if ($bool && $bool2 && $bool3) {
                    $this->gameSetService->commitTransaction();
                    $bkDt = ['result' => 0, 'sequence' => $sequence];
                } else {
                    $this->gameSetService->rollbackTransaction();
                    $bkDt = ['result' => 1, 'sequence' => '数据插入失败'];
                }
            } catch (\Exception $e) {
                $bkDt = ['result' => -1, 'sequence' => '异常'];
            }
        } else {
            try {
                $where = ['sequence' => $sequence];
                $gameInfo = $this->gameSetService->fetch($where);
                if (empty($gameInfo)) {
                    $bkDt = ['result' => 1, 'sequence' => '无数据可复制'];
                } else {
                    $sequence = $this->id();
                    $gameInfo = [
                        'sequence' => $sequence, 'meet_id' => $meetId,
                        'gameTime' => $gameInfo[0]['gameTime'], 'bgMusic' => $gameInfo[0]['bgMusic'],
                        'limit' => $gameInfo[0]['limit']
                    ];
                    $redTeamInfo = [
                        'sequence' => $sequence, 'team_name' => '红队',
                        'team_image' => '/img/red.png', 'type' => 1
                    ];
                    $blueTeamInfo = [
                        'sequence' => $sequence, 'team_name' => '蓝队',
                        'team_image' => '/img/blue.png', 'type' => 2
                    ];
                    $this->gameSetService->beginTransaction();
                    $this->teamsService->delete(array('sequence' => $sequence));
                    $this->gameSetService->delete(array('sequence' => $sequence));
                    $bool = $this->teamsService->insert($redTeamInfo);
                    $bool2 = $this->teamsService->insert($blueTeamInfo);
                    $bool3 = $this->gameSetService->insert($gameInfo);
                    if ($bool && $bool2 && $bool3) {
                        $this->gameSetService->commitTransaction();
                        $bkDt = ['result' => 0, 'sequence' => $sequence];
                    } else {
                        $this->gameSetService->rollbackTransaction();
                        $bkDt = ['result' => 1, 'sequence' => '数据插入失败'];
                    }
                }
            } catch (\Exception $e) {
                $bkDt = ['result' => -1, 'sequence' => '异常'];
            }
        }
        echo json_encode($bkDt);
        exit;
    }
    // 删除兵器
    public function delAction()
    {
        $data = $this->getParamValue('data');
        $sequence = $data['sequence'];
        $meetId = $data['meet_id'];

        try {
            $roundKey = "game_round:{$meetId}_{$sequence}";
            $round = $this->redis->get($roundKey);
            $gameStatusInfoKey = "game_status:{$meetId}_{$sequence}_$round";
            $status = $this->redis->hGet($gameStatusInfoKey, 'status');
            if ($status == 1) {
                $redis = $this->redis;
                $gameInfoKey = "game_set:{$meetId}_{$sequence}";
                $redTeamInfoKey = "teams:{$sequence}_1";
                $blueTeamInfoKey = "teams:{$sequence}_2";
                $redis->multi();
                $b1 = $redis->del($roundKey);
                $b2 = $redis->del($gameInfoKey);
                $b3 = $redis->del($redTeamInfoKey);
                $b4 = $redis->del($blueTeamInfoKey);
                $b5 = $redis->del($gameStatusInfoKey);
                if ($b1 && $b2 && $b3 && $b4 && $b5) {
                    $bkDt = ['result' => 0]; // 'msg' => '删除成功！'];
                    $redis->exec();
                } else {
                    $bkDt =['result' => 2]; // 'msg' => '删除失败！'];
                    $redis->discard();
                }
            } else {
                $bkDt = ['result' => -1]; //"游戏进行中或者已经参数数据，不能删除！"];
            }
        }catch(Exception $e){
            file_put_contents('del_bahe_error.txt', __FILE__ .  __CLASS__  . __FUNCTION__  . $e->getMessage());
            $bkDt = ['result' => -1, 'msg' => $e->getMessage()];
        }
        echo json_encode($bkDt);exit;
    }

    // 析构函数释放Redis连接
    public function __destruct()
    {
        $this->redis->close();
    }
}